Skip to content

fix(mcp): validate_expression keeps the hidden __search companion out of scope - #33451

Queued
objectstack-fleet[bot] wants to merge 9 commits into
mainfrom
claude/area-A4-33338
Queued

objectstack-fleet[bot] wants to merge 9 commits into
mainfrom
claude/area-A4-33338

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread
Fixes #33338
Clause-②: yes (widening) — @objectstack/spec/data gains the SEARCH_COMPANION_FIELD constant; @objectstack/objectql re-exports the same value it exported before.
Metadata-protocol: none

维护者速读

  • 改了什么:MCP 工具 validate_expression 不再在 inScope.fields 里列出隐藏的 __search 搜索伴生列;表达式里读它(如 record.__search)现在按 unknown-field 拒收,与 os validate 的判定一致。
  • 为什么改:这一列对调用方不可见(所有读路径都会剥掉它),但 AI 读到列表后会写出引用它的表达式,工具答 ok 而发布门禁拒收,工具和门禁两套答案。
  • 第二版(复审后 CI 超时):第一版在首次调用时加载整个引擎包只为读一个字段名,测试里首次调用超过 5 秒。现在字段名放进 @objectstack/spec/data(SEARCH_COMPANION_FIELD),引擎和 MCP 都读这一个常量,MCP 不再在运行时依赖引擎。首次调用从 5.4 秒降到 60 毫秒。
  • 风险与回滚:spec 新增一个导出常量(patch:不改元数据协议),引擎照旧以同名导出;其他字段照旧;回滚即撤销本 PR。
  • 先看:packages/spec/src/data/search-fields.ts(新常量)、packages/mcp/src/mcp-http-tools.ts(跳过伴生列)、packages/objectql/src/search-companion.ts(改为转出)。
  • 需要你做的:无,区内复审后落地。

What changes

  • validate_expression built its field list from the object as the caller is served it. Where pinyin search is on, that object carries the hidden __search companion beside the declared fields, so the tool listed __search in inScope.fields and answered ok: true for record.__search != ''. os validate judges an expression against the declared and injected columns only, so the same rule fails there with unknown-field, and every record read strips the column.
  • The tool now skips the companion when it builds the field list it judges and lists. Only __search is removed: other hidden system columns (organization_id, owning_business_unit_id, queue) are injected columns an expression may read, and os validate accepts them. Both transports share this handler.
  • Where the name lives (second revision). The first revision imported SEARCH_COMPANION_FIELD from @objectstack/objectql lazily on the first call. Under the test source alias that first call transformed the engine barrel and outran vitest's 5 s budget (Test Core (7/8): mcp-validate-expression.option-labels.test.ts › LIT, reproduced locally at 5433 ms; the lean /core entry still took about 2 s, and 3.3 s under load). The name now lives in the protocol as SEARCH_COMPANION_FIELD in @objectstack/spec/data, next to the search-field resolution that already documents the companion. @objectstack/objectql provisions and strips the column under that constant and re-exports it unchanged, and @objectstack/mcp imports it statically from the spec. mcp's dependency on the engine becomes a devDependency (the pin provisions the companion with the engine's own provisionSearchCompanion). One name, no engine load for a string.

Tests

  • New top-level describe in packages/mcp/src/mcp-validate-expression.test.ts, served by the real producers (applyInjectedSystemColumns, provisionSearchCompanion, describeServedObject): the served object carries the companion; inScope.fields lists name, email, created_at and not __search; a read of __search is refused unknown-field at the validation, formula and flow_condition sites, as validateStackExpressions refuses it. Pre-fix red and the ablation of the filter line are recorded in the first revision (2 of 3 red).
  • The timeout: the LIT case ran 5433 ms (red) on the first revision and 60 ms at the final head.

Verification

Local runs at the final head (after merging origin/main)
  • @objectstack/mcp: vitest 64/64 files, 1177/1177 tests; typecheck OK. @objectstack/spec src/data: 169/169 files, 6230 passed, 1 todo. @objectstack/objectql search suites: 11/11 files, 205/205 tests.
  • dispatch-gates.mjs --commands: 104 families derived and run, exit codes recorded. All exit 0 after gen:api-surface and gen:export-origins were committed and spec was rebuilt, except check:generated, exit 1, whose only remaining item is test-typecheck-debt.json. That is a directional ratchet this diff does not touch (no spec test changes; the file last changed on main 2026-11-13), and the gate itself says not to regenerate it unless check:test-typecheck asks.

🤖 Generated with Claude Code

https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC

@github-actions github-actions Bot added size/s dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 14, 2026
@github-actions

github-actions Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

2 anchor(s) derived from 3 changed package(s); no hand-written page names any of them. ⚠️ 3 changed file(s) yielded no anchor (packages/mcp/vitest.config.ts, packages/spec/api-surface/data.json, packages/spec/export-origins/data.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 3 changed file(s) yielded no anchor (packages/mcp/vitest.config.ts, packages/spec/api-surface/data.json, packages/spec/export-origins/data.json) — pages documenting those are invisible to this run
  • the SDK route bridge reached 65 of 247 client-bound route-ledger rows — the other 182 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 182: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 59 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 123 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 179 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json e40cd1e28dd79e60e7f4be0db06f071f3f962574 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from a70779241a49f88b758dc6a212e3ed0d7071d5c6 — the merge of head 3c1cdfab46a834fff8cbbe27c931c78b2560dae2 into base e40cd1e28dd79e60e7f4be0db06f071f3f962574, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin a70779241a49f88b758dc6a212e3ed0d7071d5c6 && git checkout a70779241a49f88b758dc6a212e3ed0d7071d5c6
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e40cd1e28dd79e60e7f4be0db06f071f3f962574 3c1cdfab46a834fff8cbbe27c931c78b2560dae2 && git checkout -B drift-repro e40cd1e28dd79e60e7f4be0db06f071f3f962574 && git merge --no-ff 3c1cdfab46a834fff8cbbe27c931c78b2560dae2

node scripts/docs-audit/affected-docs.mjs --json e40cd1e28dd79e60e7f4be0db06f071f3f962574

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract-review-claim: session_016WV4cxDxAYxdtDhtR1kQQe · head 8fd1945 · 2026-11-14T21:33Z

review#2 (server area pilot, A4).

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Review: PASS

Head: 8fd19455fb69d60ef3eb2a02cda85c590634bc7a · reviewer review#2 (session_016WV4cxDxAYxdtDhtR1kQQe) · area A4 · Fixes #33338

Checked:

  • Right place. The inScope.fields list and the field set the validator judges against are both built in validate_expression (packages/mcp/src/mcp-http-tools.ts), not in runtime domains/mcp.ts as the card guessed. Skipping the companion there fixes the list and the verdict together. Pinned: inScope.fields keeps name, email and created_at and drops __search, and record.__search != '' is refused unknown-field at the validation, formula and flow_condition sites, matching what validateStackExpressions (the os validate gate) answers for the same rule.
  • One name, not a second list (the card's constraint). The filter reads the engine's own SEARCH_COMPANION_FIELD instead of a literal, the same import plugin-pinyin-search already uses, and the fixture is stamped by the engine's own provisionSearchCompanion. Filtering on the stamped hidden: true would have been wrong, because an author field may be hidden in the UI and still be readable in expressions.
  • Clause-②: no is accepted. An expression the gate already refused is now refused here too (aligning the advisory tool with the gate, the same shape as mcp: validate_expression still answers ok where the validation/formula gate refuses (null-guard, undeclared hop field, and the rest of the gate's private passes) #32872's validate_expression parity). inScope.fields loses a column no read ever served. No export moves.

On the dependency cost you asked about: acceptable.

  • No cycle: @objectstack/objectql does not depend on @objectstack/mcp, nor does anything below it.
  • Every in-repo consumer of @objectstack/mcp (cli, verify, the QA packages) already depends on @objectstack/objectql, and a host that serves MCP has already loaded the engine, so the lazy import() resolves to an already-loaded module there.

Nits (optional):

  • N1: import from the lean entry @objectstack/objectql/core (ADR-0076), which re-exports SEARCH_COMPANION_FIELD and provisionSearchCompanion without pulling the barrel's @objectstack/metadata-protocol graph into a process that has not loaded it yet (a standalone stdio MCP). Adjust the vitest alias to match (../objectql/src/core.ts).
  • N2: packages/mcp is outside the pilot's leased paths (server#7, epic [Epic] MCP: what an agent can read and write on the HTTP MCP door, and answers that agree with the gate #32897). Before arming, check that no open server#7 PR changes the validate_expression handler in mcp-http-tools.ts.

CI at review time: 11 success, 24 in progress, none failed. Landing needs all green.


Generated by Claude Code

…objectql entry

The first validate_expression call imported the @objectstack/objectql barrel,
whose metadata-protocol graph a standalone process has not loaded; under the
source alias that first call outran a 5 s test budget. Load
SEARCH_COMPANION_FIELD from @objectstack/objectql/core (ADR-0076) instead.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
… not the engine

The first validate_expression call imported the engine to read one constant;
under the test source alias that first call outran a 5 s budget, and in a
standalone process it loads the engine for a string. The name now lives in
@objectstack/spec/data as SEARCH_COMPANION_FIELD; objectql provisions under
it and re-exports it unchanged, and mcp imports it statically from the spec,
so mcp keeps objectql as a test-only dependency.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract-review-claim: session_016WV4cxDxAYxdtDhtR1kQQe · head a182226 · 2026-11-14T23:12:52Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract-review-claim: session_016WV4cxDxAYxdtDhtR1kQQe · head 3c1cdfa · 2026-11-14T23:14:56Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 3c1cdfab46a834fff8cbbe27c931c78b2560dae2
Local-runs: none
Scope: packages/spec/src/data/search-fields.ts + packages/objectql/src/search-companion.ts, packages/mcp/src/mcp-http-tools.ts, packages/spec/api-surface/data.json, packages/spec/export-origins/data.json

review#2 (server area pilot) · area A4 · Fixes #33338 · delta on my PASS at 8fd19455 (6884553156), via a182226e. The published-spec face is new in this delta, so this record replaces the earlier plain review.

① Derived judgments

  • Why the delta exists. At 8fd19455 the tool imported the engine lazily for one constant. Test Core 7/8 timed out on the first validate_expression call, because loading the objectql barrel under the source alias took seconds. Moving the name to the spec removes the engine load from the tool's path entirely. That is a better fix than my N1 (/core), which only shortened it.
  • packages/spec/src/data/search-fields.ts adds export const SEARCH_COMPANION_FIELD = '__search', a plain string constant with no schema and no parse behaviour. Its jsdoc matches what the code does: resolveSearchFields never returns it, the engine strips it on read, and the tool now leaves it out.
  • packages/objectql/src/search-companion.ts imports the constant from @objectstack/spec/data and re-exports it under the same name. The value is identical ('__search'), so every engine caller and every stored column name is unchanged. The module's own uses read the same binding.
  • packages/mcp/src/mcp-http-tools.ts imports the constant statically from @objectstack/spec/data, which mcp already depended on, and skips that one field name when building fields/fieldTypes. Every other field, injected system columns included, is listed as before. @objectstack/objectql is only a devDependency of mcp now, for the pin, so mcp gains no runtime dependency on the engine. That also resolves the dependency question from my first round.
  • api-surface/data.json and export-origins/data.json each gain exactly the one entry, with its origin src/data/search-fields.ts.
  • Tests:
    • The precondition proves that the served object really carries the companion; it is provisioned by the engine's own provisionSearchCompanion.
    • inScope.fields keeps name, email and created_at and drops the companion.
    • A read of the companion is refused unknown-field at all three sites, and os validate's validateStackExpressions refuses the same expression. That is the parity the card asks for.

② Semver level

③ Boundary flags

  • Not security sensitive. The tool now discloses one fewer field name, and that name is platform plumbing.
  • Cross-area: packages/spec/src/data/** and packages/objectql are outside A4's narrow surface, but the change is one additive constant and a same-value re-export.
  • packages/mcp is not leased in the pilot (server#7), so it stays with A4 as before.

④ Design judgment

  • Holds against the cited code. One name, owned by the protocol, read by both the engine and the tool, is the right layering: the tool needs to recognise the column, not to run the engine. Keeping objectql's export under the same name avoids a breaking move for engine callers. The alternative, a hard-coded '__search' in mcp, would be the second spelling that the earlier rounds were avoiding.
  • Holds against the scenario. The card's scenario (record.__search != '' answering ok in the tool while os validate refuses it) is now refused at all three sites, and the companion is no longer listed.
  • N1 (nit, not blocking): the spec jsdoc says "no expression may read it". The enforcement of that is the tool's skip plus the gate's declared-field universe, not anything in the spec. That is accurate as a statement of the rule, and noted only so that a later reader does not look for a spec-side refusal.

Implemented-by: claude/area-A4-33338
Reviewed-by: session_016WV4cxDxAYxdtDhtR1kQQe

VERDICT: PASS

CI on this head was still running at review time (1 success, 7 skipped, 20 in progress; the 1 cancelled run was superseded by the push). Land only once it is green; Test Core 7/8 is the one to watch.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC

ACCEPT · area A4 · head 3c1cdfa · 2026-11-14T23:40Z

  • review#2 contract record PASS at this head (comment 6885755104, CONTRACT_REVIEW_TIER, replaces the plain PASS 6884553156). Clause-② yes (widening), Metadata-protocol none, spec at patch.
  • The Test Core 7/8 timeout on the first head (8fd1945) was this PR's own cost: an engine import on the first validate_expression call. It is removed at the root, and the case runs 60 ms locally. Test Core 1–8/8 are green at this head.
  • check-governed-merges --pr 33451: NOT governed.
  • All check-runs on this head completed green, except one PR-body guards run that a later run of the same guard superseded (cancelled; the later run is green).
  • Landing under the maintainer's area go (pilot Dispatch by code area instead of by card: area leases, one PR per coupled set, follow-ups folded (pilot on domain:server after 18.4.0; maintainer launches) #33059): ready + auto-merge.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 14, 2026 23:41
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 14, 2026
Any commits made after this event will not be merged.
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 43664809991 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

分类:failure —— 按下面的日志分诊。

失败的 job(日志抽取,best effort):

  • Test Core (5/8) — 失败步骤: Run this shard's tests

    @objectstack/plugin-approvals:test:  FAIL  src/action-page-member.integration.test.ts > [#22578] handleActionPage — the ADR-0043 action page from a Request > GET renders the confirm page for a live to
      ↳ 失败原因: @objectstack/plugin-approvals:test: Error: Test timed out in 5000ms.
    

↳ 失败原因 是判读的关键:超时(Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言(AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError。 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 23 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC

Queue ejection disposal · area A4 · head 3c1cdfa · 2026-11-15T02:10Z

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 43666747033 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

分类:failure —— 按下面的日志分诊。

失败的 job(日志抽取,best effort):

  • Dogfood Regression Gate (1/3) — 失败步骤: Boot example apps and exercise real user flows

    @objectstack/dogfood:test:  FAIL   isolated  test/bare-name-one-holder-ai-family.dogfood.test.ts > agent, skill and tool names held per namespace, on a booted showcase > [#31985] a package-less tool r
      ↳ 失败原因: @objectstack/dogfood:test: Error: Test timed out in 5000ms.
    

↳ 失败原因 是判读的关键:超时(Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言(AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError。 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

  • test/bare-name-one-holder-ai-family.dogfood.test.ts — 24h 窗口内只有本 PR 撞到过,暂不汇总(再有一个不同 PR 撞到就会自动开汇总 issue)。
  • ⚠️ 24h 评论账本没读完(超过 5 页仍未读到窗口尽头),所以上面的「不同 PR 数」是下界,不是全量。

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 22 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC

Queue ejection #2 · area A4 · head 3c1cdfa · 2026-11-15T02:46Z

  • Ejecting build: 43666747033 (triage 6888131608), Dogfood Regression Gate (1/3).
  • Signature: test/bare-name-one-holder-ai-family.dogfood.test.ts › "agent, skill and tool names held per namespace, on a booted showcase" › "[objectql: narrow the phase-1 one-holder refusal from environment to namespace for tool (ADR-0150 child B, tool) #31985] a package-less tool r…", failing with "Test timed out in 5000ms".
  • This is a NEW signature: no anchor issue yet, and only this PR has hit it in 24h. The first ejection (Queue-flake anchor: src/action-page-member.integration.test.ts #33508's approvals flake) was a different signature.
  • Initial judgement: a timeout, not an assertion. This PR's diff is the SEARCH_COMPANION_FIELD constant in spec/data, objectql's re-export, and validate_expression's in-scope field list. It changes no tool, agent or skill naming or registration. But the dogfood boot imports the whole showcase, so the failing file's import closure is NOT disjoint from the diff. The three re-queue facts therefore do not all hold.
  • Branch taken: no re-queue on my own judgement. I have asked the queue-duty reviewer to rule. Nothing is pushed to this PR in the meantime.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC

Queue re-enqueue · area A4 · head 3c1cdfa · 2026-11-15T02:47Z

The queue-duty reviewer (review#1) ruled that ejection #2 (run 43666747033) is a FLAKE, a timing cliff:

  • The timed-out case does 2 PUTs and 3 install-locals.
  • The file's own control case measures one install-local at about 1.9 s on that runner, so three cost about 5.7 s against the 5000 ms budget.
  • The other 26 cases in the file passed, and this diff is not on the install or tool-row path.

The budget fix is routed to the test's owner. Re-enqueued on the same head, with nothing pushed.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 15, 2026
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 15, 2026
Any commits made after this event will not be merged.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation protocol:data size/m tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP validate_expression: inScope.fields lists the hidden __search companion field

2 participants